#include "MoveStepCalculator.h"
#include "MoveAbilityVisitor.h"
#include "BlockMoveAbilityVisitor.h"

MoveStepCalculator::MoveStepCalculator(): movingObject(0), initialCell(0)
{
}

MoveStepCalculator::~MoveStepCalculator()
{
	Clear();
}

void MoveStepCalculator::Clear()
{
	std::list<Step*>::iterator it;

	for(it = steps.begin(); it != steps.end(); ++it)
	{
		delete (*it);
	}

	steps.clear();
}

void MoveStepCalculator::SetInitialObject(GameObject* object, const Direction& direction)
{
	movingDirection = direction;
	movingObject = object;
	initialCell = 0;
}

void MoveStepCalculator::SetInitialCell(Cell& cell, const Direction& direction)
{
	movingDirection = direction;
	movingObject = 0;
	initialCell = &cell;
	
}

bool MoveStepCalculator::IsEmpty() const
{
	return steps.empty();
}

void MoveStepCalculator::GenerateSteps(Board& board)
{
	Clear();

	if (initialCell == 0 && movingObject)
	{
		if (board.IsInsideBoard(movingObject))
		{
			initialCell = &board.CellAt(movingObject);
		}
		else
		{
			MoveAbilityVisitor moveVisitor;

			movingObject->Accept(moveVisitor);

			if (moveVisitor.FoundAbility())
			{
				AddStep(movingObject, moveVisitor.MovableInterface(), &board);
			}

			initialCell = board.ObjectNeighbourAt(movingObject, movingDirection);
		}
	}

	Cell* cell = initialCell;

	bool moreCells = true;
	bool firstCell = true;
	Direction opposedMovingDirection = movingDirection.Opposed();

	while(cell && moreCells)
	{
		const std::list<GameObject*>& cellobjects = cell->GetObjects();
		std::list<GameObject*>::const_iterator it;

		moreCells = false;

		bool opposedBlock = false;
		bool normalBlock = false;

		for(it = cellobjects.begin(); it != cellobjects.end(); ++it)
		{
			MoveAbilityVisitor moveVisitor;
			BlockMoveAbilityVisitor blockVisitor;
			GameObject* neighbour = (*it);
			

			neighbour->Accept(blockVisitor);

			if (blockVisitor.FoundAbility())
			{				
				if (blockVisitor.BlockDirection() == opposedMovingDirection)
					opposedBlock = true;
				if (blockVisitor.BlockDirection() == movingDirection)
					normalBlock = true;
			}

			neighbour->Accept(moveVisitor);

			if (moveVisitor.FoundAbility())
			{
				AddStep(neighbour, moveVisitor.MovableInterface(), &board);
				moreCells = true;
			}
		}

		if ((moreCells && normalBlock) || (opposedBlock && !firstCell))
		{
			printf("MOVE BLOCKED\n");
			Clear();

			return;
		}

		cell = board.NeighbourAt(*cell, movingDirection);
		firstCell = false;
	}
}

void MoveStepCalculator::AddStep(GameObject* object, Movable* movable, Board* board)
{
	MoveStep* step = new MoveStep();

	step->SetObject(object, movable);
	step->SetBoard(board);
	step->SetDirection(movingDirection);

	steps.push_back(step);
}

void MoveStepCalculator::Execute()
{
	std::list<Step*>::iterator it;

	for(it = steps.begin(); it != steps.end(); ++it)
	{
		(*it)->Execute();
	}
}


